#include "objetscene.h"


//--------------------- Constructeurs et destructeur -------------------

/* ****************************************************************
 * Constructeur par défault
 * **************************************************************** */
ObjetScene::ObjetScene()
{
    _materiau = new Materiaux();
    _habillage = new HCouleur();
}

/* ****************************************************************
 * Constructeur avec une liste de faces
 * @param faces : les faces du nouvel objet
 * **************************************************************** */
ObjetScene::ObjetScene(QList<Face*>  faces)
    : _faces(faces)
{
    _materiau = new Materiaux();
    _habillage = new HCouleur();
    majPointsObjet(_faces);
}

/* ****************************************************************
 * Constructeur avec une liste de faces et
 * la liste des points composant les faces.
 * @param faces : les faces du nouvel objet
 * @param ensemblePoints : l'ensemble des points de l'objet
 * **************************************************************** */
ObjetScene::ObjetScene(QList<Face*>  faces, QList<Point*> ensemblePoints)
    : _faces(faces), _ensemblePointsFaces(ensemblePoints)
{
    _materiau = new Materiaux();
    _habillage = new HCouleur();
}

/* ****************************************************************
 * Constructeur avec une liste de faces
 * @param faces : les faces du nouvel objet
 * @param habillage : l'habillage de la face
 * @param materiau : le materiau de la face
 * **************************************************************** */
ObjetScene::ObjetScene(QList<Face*>  faces, Habillage& habillage, Materiaux& materiau)
    : _faces(faces)
{
    _materiau = &materiau;
    _habillage = &habillage;
    majPointsObjet(_faces);
}

/* ****************************************************************
 * Constructeur avec une liste de faces
 * @param faces : les faces du nouvel objet
 * @param habillage : l'habillage de la face
 * @param materiau : le materiau de la face
 * **************************************************************** */
ObjetScene::ObjetScene(QList<Face*>  faces, Habillage& habillage, Materiaux& materiau, QList<Transformation*> transformations)
    : _faces(faces), _transformations(transformations)
{
    _materiau = &materiau;
    _habillage = &habillage;
    majPointsObjet(_faces);
}

/* ****************************************************************
 * Constructeur par recopie
 * @param objetScene : objet à recopier
 * **************************************************************** */
ObjetScene::ObjetScene(const ObjetScene& objetScene)
{
    for(int i = 0; i < objetScene._faces.size(); ++i)
    {
        this->_faces.push_back((new Face(*objetScene._faces[i])));
    }

    _materiau = objetScene._materiau;
    _habillage = objetScene._habillage;
    _transformations = objetScene._transformations;
}

/* ****************************************************************
 * Destructeur
 * **************************************************************** */
ObjetScene::~ObjetScene()
{
    delete _materiau;

    for(int i = 0; i < _transformations.size(); ++i)
    {
        delete _transformations[i];
    }

    for(int i = 0; i < _faces.size(); ++i)
    {
        delete _faces[i];
    }

    for(int i = 0; i < _ensemblePointsFaces.size(); ++i)
    {
        delete _ensemblePointsFaces[i];
    }

}

//----------------------------------------------------------------------
//--------------------- Méthodes ---------------------------------------

/* ****************************************************************
 * Fonction permettant d'ajouter une face
 * @param face : le face à rajouter
 * @param majListePoints : indique si l'on doit mettre à jour
 *                         l'ensemble des points de l'objet.
 * **************************************************************** */
void ObjetScene::ajouterFace(Face& face, bool majListePoints)
{
    _faces.push_back(&face);

    if(majListePoints)
        majPointsObjet(face);
}

/* ****************************************************************
 * Fonction permettant d'ajouter une transformation
 * @param transformation : la transformation à rajouter
 * **************************************************************** */
void ObjetScene::ajouterTransformation(Transformation& transformation)
{
    _transformations.push_back(&transformation);
}

/* ****************************************************************
 * Fonction permettant de récupérer le nombre de faces
 * @return int : le nombre de faces de l'objet
 * **************************************************************** */
int ObjetScene::getNbFaces()
{
    return _faces.size();
}

/* ****************************************************************
 * Fonction permettant de supprimer une face
 * @param i : indice de la face à supprimer
 * **************************************************************** */
void ObjetScene::supprimerFace(int i)
{
    if(i < 0 || i >= _faces.size())
    {
        throw std::string("ObjetScene.supprimerFace : erreur, l'indice i est hors limite.");
    }

    _faces.removeAt(i);
}

/* ****************************************************************
 * Fonction renvoyant le centre de gravité de l'objet
 * @return Point : le centre de gravité de l'objet
 * **************************************************************** */
Point& ObjetScene::getCentreGravite()
{
    GLfloat x = 0.0, y = 0.0, z = 0.0;

    for(size_t i = 0; i < _faces.size(); ++i)
    {
        Point* p = &_faces[i]->getCentreGravite();

        x += p->getX();
        y += p->getY();
        z += p->getZ();
    }

    if( _faces.size() != 0)
    {
        x /= _faces.size();
        y /= _faces.size();
        z /= _faces.size();
    }

    return *(new Point(x, y, z));
}

/* ****************************************************************
 * Fonction de dessin, on dessine les faces une par une
 * **************************************************************** */
void ObjetScene::dessiner()
{
    //On utilise le materiau
    _materiau->initialisation();

    //On utilise l'habillage
    _habillage->utiliser();

    glPushMatrix();
        //On effectue les transformations
        for(int i = 0; i < _transformations.size(); ++i)
        {
            _transformations[i]->utiliser();
        }

        //On dessine les faces
        for(int i = 0; i < _faces.size(); ++i)
        {
            _faces[i]->dessiner();
        }
    glPopMatrix();
}

/* ****************************************************************
 * Fonction permettant de mettre à jour l'ensemble des points que
 * l'objet utilise.
 * @param face : la face à rajouter à l'objet
 * **************************************************************** */
void ObjetScene::majPointsObjet(Face& face)
{
    bool trouve = false;

    for(int i = 0; i < face.getNbSommets(); ++i)
    {
        trouve = false;

        //Parcours de la liste des points déjà enregistrés
        for(int j = 0; !trouve && j < _ensemblePointsFaces.size(); ++j)
        {
            if(&face.getSommet(i).getPoint() == _ensemblePointsFaces[j])
                trouve = true;
        }

        //Si on n'a pas trouvé le point, on le rajoute à la liste
        if(!trouve)
            _ensemblePointsFaces.push_back(&face.getSommet(i).getPoint());
    }
}

/* ****************************************************************
 * Fonction permettant de mettre à jour l'ensemble des points que
 * l'objet utilise pour rajouter une liste de faces
 * @param face : la face à rajouter à l'objet
 * **************************************************************** */
void ObjetScene::majPointsObjet(QList<Face*> listeFaces)
{
   for(int i = 0; i < listeFaces.size(); ++i)
   {
        majPointsObjet(*listeFaces[i]);
   }
}

//----------------------------------------------------------------------
//--------------------- Accesseurs -------------------------------------
/* ****************************************************************
 * Fonction permettant récupérer le materiau de l'objet de la scène
 * @return Materiau : le materiau de l'objet
 * **************************************************************** */
Materiaux& ObjetScene::getMateriau()
{
    return *this->_materiau;
}

/* ****************************************************************
 * Fonction permettant récupérer l'habillage de l'objet
 * @return Habillage
 * **************************************************************** */
Habillage& ObjetScene::getHabillage()
{
    return *this->_habillage;
}


/* ****************************************************************
 * Fonction permettant de définir l'habillage de l'objet
 * @param h : le nouvel habillage
 * **************************************************************** */
void ObjetScene::setHabillage(Habillage& h)
{
    this->_habillage = &h;
}

//----------------------------------------------------------------------
//--------------------- Surcharge des opérateurs -----------------------

//----------------------------------------------------------------------
